#include "glut.h"
#include <stdio.h>
#include <time.h>		// clock()
#include "Cell.h"
#include "drawing.h"
#include "circle.h"
#include "line.h"
#include "Map.h"
#include "Piece.h"
#include "Player.h"
#include "al.h"
#include "alc.h"
#include "alut.h"
#define SCREEN_WIDTH		800
#define SCREEN_HIEGHT		600
#define SCREEN_POSITION_X	10
#define SCREEN_POSITION_Y	50
#define FIRST_LEVEL_RED		255
#define FIRST_LEVEL_GREEN	255
#define FIRST_LEVEL_BLUE	0
#define MAP_HEIGHT			13
#define MAP_WIDTH			7
#define NUMBER_OF_PLAYERS	4


//Bad global variables! But it's necessary.
Map map;
Player players[NUMBER_OF_PLAYERS]; //A static array right now, it won't be difficult to change it to a dynamic later.

/** This function converts screen coordinates into OpenGL coordinates 
	http://nehe.gamedev.net/data/articles/article.asp?article=13
*/

bool checkForNextFloor() //This function will check to see if ALL SURVIVAL SPOTS *even the one on the fourth* has been taken.
{
	for(int row = 0; row < MAP_HEIGHT; row++)
	{
		for(int col = 0; col < MAP_WIDTH; col++)
		{
			if(map.getCell(row, col).getSurvive() && map.getCell(row, col).drawned()) //This means it's a survival spot.
			{
				//If it's NOT taken, return false. Get out of this as early as possible for optimization.
				if(!map.getCell(row, col).getTaken())
					return false;
			} //If it gets here, it means that it HAS been taken.
		}
	}
	//If it gets all the way down here, it means that ALL THE SURVIVAL SPOTS HAVE BEEN TAKEN. Return true.
	return true;
}

void goToNextFloor()
{
	//This will erase all the pieces that ARE NOT ON survival spots. Ouch. Luckily, this will hopefully work as planned. T_T
	for(int row = 0; row < MAP_HEIGHT; row++)
	{
		for(int col = 0; col < MAP_WIDTH; col++)
		{
			for(int currentPlayer = 0; currentPlayer < NUMBER_OF_PLAYERS; currentPlayer++)
			{
				if(!map.getCell(row, col).getSurvive() && map.getCell(row, col).drawned())
				//This will have to erase the player piece, and set taken to false.
					//There is a piece here. Erase it.
				{
					//Prepare for a long ass if statement.
					int tooLazy;
					tooLazy = players[currentPlayer].findPiece(map.getCell(row, col).getX(), map.getCell(row, col).getY());
					if(tooLazy != -1)
					{
						//The player has a piece IN THIS POSITION. GET RID OF IT.
						players[currentPlayer].findPiece(tooLazy)->setDraw(false);
						map.getCell(row, col).take();
					}
				}
			}
		}
	}
}


V2DF GetOGLPos(int x, int y)
{
	GLint viewport[4];			// Where The Viewport Values Will Be Stored
	GLdouble modelview[16];		// Where The 16 Doubles Of The Modelview Matrix Are To Be Stored
	GLdouble projection[16];	// Where The 16 Doubles Of The Projection Matrix Are To Be Stored
	GLfloat winX, winY, winZ;	// Holds Our X, Y and Z Coordinates
	GLdouble posX, posY, posZ;	// Hold The Final Values

	glGetDoublev( GL_MODELVIEW_MATRIX, modelview );		// Retrieve The Modelview Matrix	
	glGetDoublev( GL_PROJECTION_MATRIX, projection );	// Retrieve The Projection Matrix
	glGetIntegerv( GL_VIEWPORT, viewport );				// Retrieves The Viewport Values (X, Y, Width, Height)

	winX = (float)x;						// Holds The Mouse X Coordinate
	winY = (float)viewport[3] - (float)y;	// Subtract The Current Mouse Y Coordinate From The Screen Height.
	glReadPixels( x, int(winY), 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ );
	gluUnProject( winX, winY, winZ, modelview, projection, viewport, &posX, &posY, &posZ);

	return V2DF(posX, posY);
}



/** @param x/y the coordinate of where the mouse is */
void passiveMotion(int x, int y)
{
	V2DF click(GetOGLPos(x,y));
	for(int row = 0; row < MAP_HEIGHT; ++row)
	{
		for(int col = 0; col < MAP_WIDTH; ++col)
		{
			if(map.getCell(row,col).getPosition().isWithinRadius(click) && map.getCell(row,col).drawned())
			{
			//	printf("INSIDE CIRCLE at index: %d, %d\n", row,col);
			}
		}
	}

}
//I have an idea of how to do this. But dear god, I don't want to do it. It would need dozens of global variables (if only so I could initialize them outwards.)

void mouseFunction(int button, int state, int x, int y)
{
	bool moved = false;
	V2DF click(GetOGLPos(x, y));
	static bool setUp = false; //This will automatically be set to false: Which is perfect. And thanks to being static.
	if(state == 0)
	{
		if(setUp == false) //Meaning that NONE of the pieces have been set up yet. more static variables, here we come! 
		{
			static int totalPieces = 0; //Again, this will be set to zero. I'm pretty sure.
			static int currentPlayer = 0; //This will be the current player, in the setup.
			static int currentPiece = 0;
			for(int row = 0; row < MAP_HEIGHT; row++)
			{
				for(int col = 0; col < MAP_WIDTH; col++)
				{
					if(map.getCell(row, col).getPosition().isWithinRadius(click) && map.getCell(row, col).drawned()) //They clicked inside a cell.
					{
						if(	((col == 3) && (row == 0 || row == 12)) ||
							((col == 2 || col == 4) && (row == 1 || row == 11)) ||
							((col == 1 || col == 5) && (row == 2 || row == 10)) ||
							((col == 0 || col == 6) && (row == 3 || row == 5 || row == 7 || row == 9)))
						{
							//yay more if statements!
							if(map.getCell(row, col).getTaken() == false) //It's not taken yet! Eligible!
							{
//								printf("%d", players[0].findPiece(0).getDraw());

								//Debug code. once this works, get rid of this comment and the next few lines.
								printf("Click X: %f, Click Y: %f \n", click.getX(), click.getY());
								//Until here, actually.

								players[currentPlayer].findPiece(currentPiece)->move(map.getCell(row, col).getX(), map.getCell(row, col).getY()); //Can anybody else figure this out and WHY IT WON'T WORK!?!?!?!!?!?!?!?!?!?!?11!!
								printf("Piece X: %f, Piece Y: %f \n", players[currentPlayer].findPiece(currentPiece)->getX(),players[currentPlayer].findPiece(currentPiece)->getY());
//								printf("%d", players[0].findPiece(0).getDraw());
								currentPlayer += 1;
								map.getCell(row, col).take();
								printf("Eligible.\n");
								totalPieces += 1;
							}
							else //Oh, it IS taken! Choose another spot!
							{
								printf("Not Eligible.\n");
							}
						}
					}
				}
			}
			if(currentPlayer >= NUMBER_OF_PLAYERS)
			{
				currentPiece += 1; //Moves to the next piece.
				currentPlayer = 0; //Goes back to the first person.
			}
			if(totalPieces >= 18)
			{
				setUp = true;
				printf("Hi.");
			}
		}
		else
		{
			static int currentPlayer = 0;
			//Now for the basic gameplay! This is what will happen the majority of the time.
			for(int row = 0; row < MAP_HEIGHT; row++)
			{
				for(int col = 0; col < MAP_WIDTH; col++)
				{
					if(map.getCell(row, col).getPosition().isWithinRadius(click) && map.getCell(row, col).drawned())
					{
						//They've clicked on a circle. Now for some more logic.
						//Have they clicked on a piece?
						if(map.getCell(row, col).getTaken()) //This will let the computer know if that cell has a piece.
						{
							//If so, if the player color the same as the piece's owner?
							if(players[currentPlayer].findPiece(players[currentPlayer].findPiece(map.getCell(row, col).getX(), map.getCell(row, col).getY()))->getColor() == players[currentPlayer].getColor())
							{
								//Yes, apparently. Note that I can already forsee an error here: It will be VERY difficult to get the exact same points. Find some way around this.
								players[currentPlayer].findPiece(players[currentPlayer].findPiece(map.getCell(row, col).getX(), map.getCell(row, col).getY()))->select();
									//Has it already been selected?
							}
							else
							{
								printf("Wrong piece, dumbass.");
							}
						}
						else
						{
							//Is there a piece already selected?
							bool selected = false;
							int tooLazy = 0;
							for(int i = 0; i < players[currentPlayer].getNumber(); i++)
							{
								if(players[currentPlayer].findPiece(i)->getSelect())
								{
									selected = true;
									tooLazy = i;
									break;
								}
							}
							//If yes?
							if(selected)
							{
								//Then move that piece to the clicked position. And holy crap I just realized how big this function was.
								map.getCell(players[currentPlayer].findPiece(tooLazy)->getX(), players[currentPlayer].findPiece(tooLazy)->getY()).take(); //That is entirely too long.
								players[currentPlayer].findPiece(tooLazy)->move(map.getCell(row, col).getX(), map.getCell(row, col).getY());
								players[currentPlayer].findPiece(tooLazy)->select(); //Turn off the selected.
								map.getCell(row, col).take();
								currentPlayer += 1;
								if(currentPlayer >= 4)
								{
									currentPlayer = 0;
								}
								if(checkForNextFloor())
								{
									goToNextFloor();
									map.changeLevel();
								}
							}
						}
					}
				}
			}
		}
	}
	//if(state == 0) //Only get it when the mouse clicks down.
	//{
	//	static int player; //I hope...to all ungodly hope...that it's 0... because I don't know how to do this otherwise.
	//	V2DF click(GetOGLPos(x,y));
	//	for(int row = 0; row < MAP_HEIGHT; ++row)
	//	{
	//		for(int col = 0; col < MAP_WIDTH; ++col)
	//		{
	//			if(map.getCell(row, col).getPosition().isWithinRadius(click) && map.getCell(row, col).drawned())
	//			{
	//				click = map.getCell(row, col).getPosition().getPosition();
	//				player = player % NUMBER_OF_PLAYERS;
	//				if(player == 0)
	//				{
	//					bool select = false;
	//					int sel = 0;
	//					//for(int i = 0; i < testPlayer.getNumber(); i++) //Looks to see if a cell has already been selected.
	//					//{
	//					//	//if(testPlayer.findPiece(i).getSelect())
	//						/*{
	//							select = true;
	//							sel = i;
	//							break;
	//						}*/
	//					//}
	//						//testPlayer.move(testPlayer.findPiece(click.getX(), click.getY()), click.getX(), click.getY());
	//					if(select) //If there is, then it moves it to that point.
	//					{
	//						//testPlayer.move(sel, click.getX(), click.getY());
	//						moved = true;
	//					}
	//					else //Else, it sees if the one the player clicked on IS in fact, the current player's.
	//					//{
	//					//	if((testPlayer.findPiece(click.getX(), click.getY()) != -1) && //Makes sure there's one to begin with
	//					//		(testPlayer.findPiece(testPlayer.findPiece(click.getX(), click.getY())).getColor() == 0)) //Checks the color to see if it IS the current players.
	//					//		testPlayer.findPiece(testPlayer.findPiece(click.getX(), click.getY())).select();
	//						moved = false;
	//					}
	//				/*else if(player == 1) //I'm commenting out this code until further notice due to the fact I want to make sure what I have in mind works.
	//				{
	//					if(player2.findPiece(player2.findPiece(click.getX(), click.getY())).getSelect())
	//					{
	//						player2.move(player2.findPiece(click.getX(), click.getY()), click.getX(), click.getY());
	//						moved = true;
	//					}
	//					else
	//					{
	//						if((player2.findPiece(click.getX(), click.getY() != -1) &&
	//							(player2.findPiece(player2.findPiece(click.getX(), click.getY())).getColor() == 1)))
	//							player2.findPiece(testPlayer.findPiece(click.getX(), click.getY())).select();
	//						moved = false;
	//					}
	//				}*/
	//			}
	//		}
	//	}
	//	glutPostRedisplay();
	//	if(moved) //This will allow us to easily control when to switch to the next player.
	//	{
	//		player++;
	//	}
	//	moved = false;
	//}
}

void keyboard(unsigned char key, int x, int y)
{
	switch(key)
	{
	case 'w':	break;
	case 'a':	break;
	case 's':	break;
	case 'd':	break;
	}
	glutPostRedisplay();
}

int g_then = clock();
void gameUpdate(int a_timeDelay)
{
	int now = clock(), passed = now - g_then;
	g_then = now;
	glutPostRedisplay();
	glutTimerFunc(a_timeDelay, gameUpdate, a_timeDelay);
}
/** the display method for our GLUT program */
void display()
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//Clear the screen and the Depth Buffer
	glColor3ub(FIRST_LEVEL_RED, FIRST_LEVEL_GREEN, FIRST_LEVEL_BLUE);		// explicit about the color
	glLoadIdentity();

	// draw shapes

	map.glDraw();

	for(int i = 0; i < NUMBER_OF_PLAYERS; i++)
	{
		players[i].glDraw();
	}
	glutSwapBuffers();	// swap the draw buffers
	glFlush();
	

}
GLvoid InitGL(GLvoid);
GLvoid DrawGLScene(GLvoid);
GLvoid ReSizeGLScene(int Width, int Height);
/**
 * @param argc count of arguments passed into the program
 * @param argv values of arguments passed into the program
 */

//To get this to work again, comment out from THIS line to...
ALuint Buffer;
ALuint Source;

ALfloat SourcePos[] = {0.0, 0.0, 0.0}; //Where the sound comes from.
ALfloat SourceVel[] = {0.0, 0.0, 0.0}; //I have no idea.

ALfloat ListenerPos[] = {0.0, 0.0, 0.0}; //Where the listener currently is.
ALfloat ListenerVel[] = {0.0, 0.0, 0.0}; //I have no idea.
ALfloat ListenerOri[] = {0.0, 0.0, -1.0, 0.0, 1.0, 0.0}; //The orientation of the listener.

ALboolean loadALData()
{
	ALenum format;
	ALsizei size;
	ALvoid* data;
	ALsizei freq;
	ALboolean loop;

	alGenBuffers(1, &Buffer);
	if(alGetError() != AL_NO_ERROR)
		return AL_FALSE;

	alutLoadWAVFile("skflyingbattery.wav", &format, &data, &size, &freq, &loop);
	alBufferData(Buffer, format, data, size, freq);
	alutUnloadWAV(format, data, size, freq);

	alGenSources(1, &Source);
	if(alGetError() != AL_NO_ERROR)
		return AL_FALSE;

	alSourcei (Source, AL_BUFFER, Buffer);
	alSourcef (Source, AL_PITCH, 1.0f);
	alSourcef (Source, AL_GAIN, 1.0f);
	alSourcefv(Source, AL_POSITION, SourcePos);
	alSourcefv(Source, AL_VELOCITY, SourceVel);
	alSourcei (Source, AL_LOOPING, loop);
	if(alGetError() == AL_NO_ERROR)
		return AL_TRUE;

	return AL_FALSE;
}

void SetListenerValues()
{
	alListenerfv(AL_POSITION, ListenerPos);
	alListenerfv(AL_VELOCITY, ListenerVel);
	alListenerfv(AL_ORIENTATION, ListenerOri);
}

void KillALData()
{
	alDeleteBuffers(1, &Buffer);
	alDeleteSources(1, &Source);
	alutExit();
}

//This line. And the everything begginning with al in main.
int main(int argc, char ** argv)
{

	alutInit(&argc, argv);
	alGetError();

	if(loadALData() == AL_FALSE)
		return -1;

	SetListenerValues();
	
	alSourcePlay(Source);
	atexit(KillALData);

//	printf("Position: %d, %d", cell.getX(), cell.getY()); //This is test code to make sure the cell class can set and get stuff.
	for(int i = 0; i < NUMBER_OF_PLAYERS; i++)
	{
		players[i].setColor(i);
		players[i].setNumber(9);
		players[i].setPieces();
	}

	glutInit(&argc, argv);
	glutInitWindowSize(SCREEN_WIDTH, SCREEN_HIEGHT);
	glutInitWindowPosition(SCREEN_POSITION_X, SCREEN_POSITION_Y);
	glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
	glutCreateWindow("MidTerm");
	glutDisplayFunc(display);
	glutMouseFunc(mouseFunction);
	glutPassiveMotionFunc(passiveMotion);
	glutKeyboardFunc(keyboard);

	//1000 / FPS = millisecondWaitTime
	glutTimerFunc(0, gameUpdate, (1000/80));
	glutPostRedisplay();
	glutMainLoop();
	return 0;
}